iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0
AI & Data

用R語言玩轉文字探勘系列 第 29

[Day 29] 用R語言玩轉文字探勘案例 - 分析篇

  • 分享至 

  • xImage
  •  

文字探勘應用案例

應用案例 - 分析篇

在分析前,我們要討論的是「具體要分析什麼」,這是每次分析資料以前,要先問的問題。當然你也可以先做個EDA觀察資料,但在一般實務情況下,都會先訂框架。

我先拋磚引玉,丟幾個問題。不管資料內容長怎樣,先問:某個人、某些人講的話,有什麼會是重點?一般人講話,我們可能會看他有沒有慣用的講話模式,例如有人愛罵髒話,有人愛用成語,至於總統,我們關注他們的身份,既然他們代表國家、手握權力,那我們可能想知道他們話語中,跟國家有關的詞彙,同時也想知道他們如何運用權力,具體來說就是會如何談論哪些政策,或者說施政重點

走到這步,其實就已經不錯了,我們知道我們關心國家施政重點。當資料夠豐富,我們可以看得更細緻,例如關心國家以外,總統也有外交權力,那要怎麼跟其他國家互動?要怎麼看待兩岸關係?至於施政重點,會看重哪些面向?怎麼談論自己重視的價值?譬如說我們可以猜測,有人拼經濟、有人護安全,有人兩個都要,台灣安群、人民有錢。

知道要看的焦點之後,下一步就是方法了,我們可以怎麼看?哪些叫做重點?應該說,要怎麼量化重點?

很明顯的,前面講過看用頻率看熱門詞彙,絕對會是最基本的辦法,另外關鍵詞彙,包含
information gain、chi statistics 或者是 tf-idf 都可以拿來合適的指標。

除此之外,我們不只關注一個總統,我們關注很多總統(至少有四位),所以可以將不同總統的維度納入分析,當然,也可以以年份比較。既然以年份或總統來比較,那我們除了看詞頻以外,想要掌握某位總統講話的重點,有什麼方法呢?什麼叫做他關心的議題?

有一種作法是從分析方法來看,逐一探討可以派上用場的工具,例如想到主題模型,他是一種拿來將文本分出大方向的好工具,但他在此並不適用,為什麼?因為我們沒有很多篇文章,只有少少的幾篇文章,跟手握數百篇的應用情境不一樣。不過,這種從方法來看的做法最好在後面一點再拿來用,前面還是像上面的做法,先抓目標、再切維度,接著找指標量化,最後這一步才會落地到分析方法。

既然要抓到重點,那利用詞彙共現是個不錯的方式,因爲他的其中一個看法就是「要不一起出現、要不都不出現」(pairwise
correlation),所以我們可以用這招。此外,我們前面有提到國家的對外關係,那或許我們也能衡量提到某些國家的態度。通常這可以用情感分析,不過我認為此處並不適合。為什麼呢?因為總統能講的話篇幅有限,而且文章數太少,這種用數的還比較快,當資料量很大、跨越很多年,再來用情感分析衡量比較好,畢竟情感分析的準確性沒那麼高,樣本小的時候個人就不會想用了。我們倒是可以考慮用詞嵌入模型喔!因為裡面有空間分佈的概念,可以看台灣和美國、台灣和中國等相對位置,也能找相似詞。

以上就是分析前的一系列思路。接著我們進入程式碼部分。

library(tidyverse)
library(tidytext)
library(widyr)
library(ggraph)

df_speech_seg_unnest <- read_rds("data/國慶演說/df_speech_seg_unnest.rds")
df_stopwords <- read_table("data/df_stopword.txt", col_names = F) %>%
  rename(id = 1, text_segment = 2) %>% select(text_segment)

df_year_word_count <- df_speech_seg_unnest %>% count(year_full, year, president, text_segment, text_POS)
df_year_word_count %>% head(10)

## # A tibble: 10 × 6
##    year_full year   president text_segment text_POS        n
##        <dbl> <chr>  <chr>     <chr>        <chr>       <int>
##  1      1997 八十六 李登輝    、           Puncuation      8
##  2      1997 八十六 李登輝    。           Puncuation     10
##  3      1997 八十六 李登輝    「           Puncuation      2
##  4      1997 八十六 李登輝    」           Puncuation      2
##  5      1997 八十六 李登輝    一再         Adverb          1
##  6      1997 八十六 李登輝    一定         Adverb          1
##  7      1997 八十六 李登輝    上           Noun            5
##  8      1997 八十六 李登輝    下           Noun            1
##  9      1997 八十六 李登輝    不但         Conjunction     1
## 10      1997 八十六 李登輝    不斷         Adverb          1

### 2023年
df_year_word_count %>% filter(year_full == 2023) %>%
  arrange(desc(n)) %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  anti_join(df_stopwords) %>%
  head(20)

## # A tibble: 20 × 6
##    year_full year   president text_segment text_POS     n
##        <dbl> <chr>  <chr>     <chr>        <chr>    <int>
##  1      2023 一一二 蔡english    我們         Noun        51
##  2      2023 一一二 蔡english    臺灣         Noun        39
##  3      2023 一一二 蔡english    民主         Noun        20
##  4      2023 一一二 蔡english    世界         Noun        14
##  5      2023 一一二 蔡english    和平         Verb        14
##  6      2023 一一二 蔡english    國家         Noun        13
##  7      2023 一一二 蔡english    穩定         Verb        11
##  8      2023 一一二 蔡english    全球         Noun        10
##  9      2023 一一二 蔡english    兩岸         Noun        10
## 10      2023 一一二 蔡english    國際         Noun        10
## 11      2023 一一二 蔡english    已經         Adverb       8
## 12      2023 一一二 蔡english    感謝         Verb         8
## 13      2023 一一二 蔡english    前進         Verb         7
## 14      2023 一一二 蔡english    基礎         Noun         7
## 15      2023 一一二 蔡english    守護         Verb         7
## 16      2023 一一二 蔡english    成為         Verb         7
## 17      2023 一一二 蔡english    中華民國     Noun         6
## 18      2023 一一二 蔡english    區域         Noun         6
## 19      2023 一一二 蔡english    發展         Verb         6
## 20      2023 一一二 蔡english    維持         Verb         6

### 中華民國、台灣、美國、中國
df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
  count(text_segment) %>% head(10)

## # A tibble: 10 × 2
##    text_segment     n
##    <chr>        <int>
##  1 中華             9
##  2 中華民國        27
##  3 中華民族         6
##  4 民國             4
##  5 民國黨           1
##  6 臺灣            26
##  7 臺灣人           8
##  8 臺灣人樂         1
##  9 臺灣海峽         3
## 10 臺灣版           1

### 中華民國與台灣
df_president_roc <- df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
  filter(!str_detect(text_segment, "民國黨")) %>%
  filter(text_segment != "民國") %>%
  mutate(text_type = if_else(str_detect(text_segment, "中華|民國"), "中華民國", "臺灣")) %>%
  group_by(president, text_type) %>%
  summarise(n = sum(n))

df_president_roc

## # A tibble: 8 × 3
## # Groups:   president [4]
##   president text_type     n
##   <chr>     <chr>     <int>
## 1 李登輝    中華民國     14
## 2 李登輝    臺灣          5
## 3 蔡english    中華民國     49
## 4 蔡english    臺灣        330
## 5 陳水扁    中華民國     38
## 6 陳水扁    臺灣        285
## 7 馬英九    中華民國    121
## 8 馬英九    臺灣        252

df_president_year_roc <- df_year_word_count %>% filter(str_detect(text_segment, "中華|民國|臺灣")) %>%
  filter(!str_detect(text_segment, "民國黨")) %>%
  filter(text_segment != "民國") %>%
  filter(text_segment != "臺灣海峽") %>%
  mutate(text_type = if_else(str_detect(text_segment, "中華|民國"), "中華民國", "臺灣")) %>%
  group_by(year_full, text_type) %>%
  summarise(n = sum(n))

df_president_year_roc

## # A tibble: 53 × 3
## # Groups:   year_full [27]
##    year_full text_type     n
##        <dbl> <chr>     <int>
##  1      1997 中華民國      4
##  2      1997 臺灣          1
##  3      1998 中華民國      5
##  4      1999 中華民國      5
##  5      1999 臺灣          4
##  6      2000 中華民國      7
##  7      2000 臺灣          8
##  8      2001 中華民國      3
##  9      2001 臺灣         12
## 10      2002 中華民國      4
## # ℹ 43 more rows

### 兩岸與美國
df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|美國|大陸|日本|北京|華府|華盛頓|白宮")) %>% count(text_segment)

## # A tibble: 10 × 2
##    text_segment     n
##    <chr>        <int>
##  1 中共             6
##  2 中國            17
##  3 中國人           2
##  4 兩岸            24
##  5 北京             7
##  6 大陸            12
##  7 日本            12
##  8 美國            15
##  9 美國人           1
## 10 華府             1

df_president_foreign <- df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|北京|美國|華府")) %>%
  mutate(text_type = if_else(str_detect(text_segment, "中共|兩岸|中國|大陸|北京"), "中國", "美國")) %>%
  group_by(president, text_type) %>%
  summarise(n = sum(n))

df_president_year_foreign <- df_year_word_count %>% filter(str_detect(text_segment, "中共|兩岸|中國|北京|美國|華府")) %>%
  mutate(text_type = if_else(str_detect(text_segment, "中共|兩岸|中國|大陸|北京"), "中國", "美國")) %>%
  group_by(year_full, text_type) %>%
  summarise(n = sum(n))

### 熱門詞彙 - year
df_year_word_top <- df_year_word_count %>% group_by(year_full) %>%
  arrange(year_full, desc(n)) %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  anti_join(df_stopwords) %>%
  mutate(rn = row_number()) %>%
  filter(rn <= 10) %>%
  ungroup()

df_year_word_top_wide <- df_year_word_top %>%
  select(-text_POS, -n) %>%
  pivot_wider(names_from = rn, values_from = text_segment)

df_year_word_top_wide

## # A tibble: 27 × 13
##    year_full year   president `1`   `2`   `3`      `4`      `5`      `6`   `7`   `8`   `9`   `10` 
##        <dbl> <chr>  <chr>     <chr> <chr> <chr>    <chr>    <chr>    <chr> <chr> <chr> <chr> <chr>
##  1      1997 八十六 李登輝    我們  發展  國家     社會     中華民國 兩岸  自由  世界  基礎  成就 
##  2      1998 八十七 李登輝    國家  我們  中華民國 繁榮     奮鬥     民主  發展  社會  世界  世紀 
##  3      1999 八十八 李登輝    我們  國家  社會     國際     中華民國 兩岸  家園  方面  民眾  安全 
##  4      2000 八十九 陳水扁    我們  政府  臺灣     中華民國 兩岸     和平  安全  世界  國家  提升 
##  5      2001 九十   陳水扁    政府  臺灣  兩岸     經濟     我們     推動  民主  世紀  和平  國際 
##  6      2002 九十一 陳水扁    我們  改革  臺灣     國家     積極     國際  政黨  民主  面對  信心 
##  7      2003 九十二 陳水扁    臺灣  改革  我們     民主     經濟     相信  過去  政府  政治  今年 
##  8      2004 九十三 陳水扁    臺灣  兩岸  國際     我們     共同     應該  阿扁  和平  發展  社會 
##  9      2005 九十四 陳水扁    臺灣  政府  改革     我們     社會     國家  經濟  退休  金融  改革 
## 10      2006 九十五 陳水扁    臺灣  國家  我們     民主     自由     過去  司法  政府  中國  政治 
## # ℹ 17 more rows

### tf-idf - year
df_year_word_tfidf <- df_year_word_count %>% group_by(year_full) %>%
  arrange(year_full, desc(n)) %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  group_by(year_full, year, president, text_segment) %>%
  arrange(desc(n)) %>% filter(row_number() == 1) %>%
  filter(!text_segment %in% c("2006年","九十七年","一百","一向","七十二","(一)","(三)", "三十", "六十")) %>%
  anti_join(df_stopwords) %>% ungroup() %>%
  bind_tf_idf(text_segment, year_full, n)

df_year_word_tfidf_top <- df_year_word_tfidf %>% group_by(year_full) %>%
  filter(n > 2) %>%
  arrange(desc(tf_idf)) %>%
  mutate(rn = row_number()) %>%
  filter(rn <= 10) %>% ungroup() %>%
  arrange(year_full, rn)

df_year_word_tfidf_top_wide <- df_year_word_tfidf_top %>%
  select(year_full, president, text_segment, rn) %>%
  pivot_wider(names_from = rn, values_from = text_segment)

df_year_word_tfidf_top_wide

## # A tibble: 27 × 12
##    year_full president `1`    `2`   `3`    `4`    `5`      `6`        `7`    `8`        `9`    `10` 
##        <dbl> <chr>     <chr>  <chr> <chr>  <chr>  <chr>    <chr>      <chr>  <chr>      <chr>  <chr>
##  1      1997 李登輝    理想   成就  繁榮   兩岸   歷史     自由       世界   基礎       我們   發展 
##  2      1998 李登輝    奮鬥   繁榮  國家   我們   中華民國 民主       發展   社會       <NA>   <NA> 
##  3      1999 李登輝    登輝   家園  發生   發揮   女士     方面       重建   事實       關懷   工作 
##  4      2000 陳水扁    政權   潮流  利益   世紀   威權     兩千三百萬 方面   提升       安全   全體 
##  5      2001 陳水扁    經發會 賄選  九一一 選舉   世紀     事件       恐怖   重建       朝野   和解 
##  6      2002 陳水扁    阿扁   道路  利益   金融   改革     方面       信心   積極       政黨   代表 
##  7      2003 陳水扁    雲門   黑金  掃除   景氣   伙伴     必然       曾經   最後       憲政   相信 
##  8      2004 陳水扁    阿扁   故事  奧運   寫下   五二○    台海       應該   兩千三百萬 聯合國 族群 
##  9      2005 陳水扁    替代率 退休  金改   不當   黨產     利率       黨政軍 所得       相關   優惠 
## 10      2006 陳水扁    貪腐   司法  體制   八月份 案件     認同       分歧   加油       中部   台海 
## # ℹ 17 more rows

### 熱門詞彙 - president
df_president_word_top <- df_year_word_count %>% 
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  anti_join(df_stopwords) %>%
  group_by(president, text_segment) %>%
  summarise(n = sum(n)) %>%
  arrange(president, desc(n)) %>%
  mutate(rn = row_number()) %>%
  filter(rn <= 10) %>%
  ungroup()

df_president_word_top_wide <- df_president_word_top %>%
  select(president, text_segment, rn) %>%
  pivot_wider(names_from = rn, values_from = text_segment)

df_president_word_top_wide

## # A tibble: 4 × 11
##   president `1`   `2`   `3`   `4`   `5`      `6`      `7`   `8`   `9`   `10` 
##   <chr>     <chr> <chr> <chr> <chr> <chr>    <chr>    <chr> <chr> <chr> <chr>
## 1 李登輝    我們  國家  社會  民主  發展     中華民國 兩岸  國際  繁榮  經濟 
## 2 蔡english    我們  臺灣  國家  民主  經濟     世界     國際  社會  兩岸  發展 
## 3 陳水扁    臺灣  我們  政府  國家  民主     改革     經濟  兩岸  社會  國際 
## 4 馬英九    我們  臺灣  經濟  兩岸  中華民國 政府     國際  民主  國家  社會

### tf-idf - year
df_president_word_tfidf <- df_year_word_count %>% 
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  anti_join(df_stopwords) %>%
  group_by(president, text_segment) %>%
  summarise(n = sum(n)) %>%
  arrange(president, desc(n)) %>%
  # summarise(n = sum(n)) %>%
  filter(!text_segment %in% c("2006年","九十七年","一百","一向","七十二","(一)","(三)", "三十", "六十")) %>%
  anti_join(df_stopwords) %>% ungroup() %>%
  bind_tf_idf(text_segment, president, n)

df_president_word_tfidf_top <- df_president_word_tfidf %>% group_by(president) %>%
  filter(n > 2) %>%
  arrange(desc(tf_idf)) %>%
  mutate(rn = row_number()) %>%
  filter(rn <= 10) %>% ungroup() %>%
  arrange(president, rn)

df_president_word_tfidf_top_wide <- df_president_word_tfidf_top %>%
  select(president, president, text_segment, rn) %>%
  pivot_wider(names_from = rn, values_from = text_segment)

df_president_word_tfidf_top_wide

## # A tibble: 4 × 11
##   president `1`   `2`   `3`   `4`   `5`    `6`   `7`   `8`   `9`   `10` 
##   <chr>     <chr> <chr> <chr> <chr> <chr>  <chr> <chr> <chr> <chr> <chr>
## 1 李登輝    兄弟  登輝  父老  建國  熱烈   紀元  統一  理想  開創  世紀 
## 2 蔡english    現場  國造  變局  印太  好朋友 守護  世代  毒品  重組  全球 
## 3 陳水扁    阿扁  投票  名義  台海  輪替   政黨  美元  韓國  黑金  伙伴 
## 4 馬英九    協議  鄉親  英九  簽訂  協定   簽證  閣下  活路  今年  全球

### 計算 correlation
word_cors_tsai <- df_speech_seg_unnest %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  filter(president == "蔡english") %>%
  group_by(text_segment) %>%
  filter(n() >= 10) %>%
  pairwise_cor(text_segment, sentence_id, sort = TRUE)

word_cors_tsai %>% filter(row_number() %% 2 == 0)

## # A tibble: 23,653 × 3
##    item1 item2 correlation
##    <chr> <chr>       <dbl>
##  1 大會  主席        0.798
##  2 國人  同胞        0.764
##  3 院長  主席        0.760
##  4 主席  院長        0.760
##  5 主席  現場        0.731
##  6 貴賓  網路        0.692
##  7 現場  貴賓        0.666
##  8 網路  主席        0.663
##  9 主席  網路        0.663
## 10 服務  增加        0.663
## # ℹ 23,643 more rows

word_cors_ma <- df_speech_seg_unnest %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  filter(president == "馬英九") %>%
  group_by(text_segment) %>%
  filter(n() >= 10) %>%
  pairwise_cor(text_segment, sentence_id, sort = TRUE)

word_cors_ma %>% filter(row_number() %% 2 == 0)

## # A tibble: 17,391 × 3
##    item1  item2 correlation
##    <chr>  <chr>       <dbl>
##  1 副總統 院長        0.893
##  2 院長   閣下        0.865
##  3 各位   鄉親        0.848
##  4 維持   現狀        0.802
##  5 副總統 閣下        0.772
##  6 九二   共識        0.757
##  7 大會   閣下        0.641
##  8 簽署   協議        0.626
##  9 共和國 閣下        0.613
## 10 鄉親   父老        0.593
## # ℹ 17,381 more rows

word_cors_chen <- df_speech_seg_unnest %>%
  filter(!text_POS %in% c("Puncuation")) %>%
  filter(str_length(text_segment) > 1) %>%
  filter(president == "陳水扁") %>%
  group_by(text_segment) %>%
  filter(n() >= 10) %>%
  pairwise_cor(text_segment, sentence_id, sort = TRUE)

word_cors_chen %>% filter(row_number() %% 2 == 0)

## # A tibble: 15,931 × 3
##    item1 item2  correlation
##    <chr> <chr>        <dbl>
##  1 中華  共和國       0.873
##  2 公民  投票         0.812
##  3 同胞  國人         0.783
##  4 政黨  輪替         0.672
##  5 各位  伙伴         0.671
##  6 各位  貴賓         0.634
##  7 貴賓  伙伴         0.631
##  8 正義  公平         0.588
##  9 自由  人權         0.535
## 10 體制  憲政         0.502
## # ℹ 15,921 more rows

上一篇
[Day 28] 用R語言玩轉文字探勘案例 - 清資料與斷詞篇
下一篇
[Day 30] 用R語言玩轉文字探勘案例 - 視覺化篇
系列文
用R語言玩轉文字探勘30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言